home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1994 March
/
Internet Info CD-ROM (Walnut Creek) (March 1994).iso
/
networking
/
ip
/
ka9q
/
src.arc
/
PKTDRVR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1989-08-19
|
10KB
|
398 lines
/* Driver for FTP Software's packet driver interface */
#include <stdio.h>
#include <dos.h>
#include "global.h"
#include "proc.h"
#include "mbuf.h"
#include "enet.h"
#include "ax25.h"
#include "slip.h"
#include "kiss.h"
#include "iface.h"
#include "ec.h"
#include "timer.h"
#include "arp.h"
#include "trace.h"
#include "pktdrvr.h"
#include "config.h"
static int access_type __ARGS((int intno,int if_class,int if_type,int if_number,
char *type,unsigned typelen,INTERRUPT (*receiver) __ARGS((void)) ));
#ifdef notdef
static int driver_info __ARGS((int intno,int handle,int *version,
int *class,int *type,int *number,int *basic));
#endif
static int release_type __ARGS((int intno,int handle));
static int get_address __ARGS((int intno,int handle,char *buf,int len));
static int pk_raw __ARGS((struct iface *iface,struct mbuf *bp));
static int pk_stop __ARGS((struct iface *iface));
static int send_pkt __ARGS((int intno,char *buffer,unsigned length));
static INTERRUPT (*Pkvec[])() = { pkvec0,pkvec1,pkvec2 };
static struct pktdrvr Pktdrvr[PK_MAX];
static unsigned int Npk;
static int Derr;
/* Send raw packet (caller provides header) */
static int
pk_raw(iface,bp)
struct iface *iface; /* Pointer to interface control block */
struct mbuf *bp; /* Data field */
{
register struct pktdrvr *pp;
int16 size;
struct mbuf *bp1;
pp = &Pktdrvr[iface->dev];
size = len_mbuf(bp);
switch(pp->class){
case CL_ETHERNET:
dump(iface,IF_TRACE_OUT,TYPE_ETHER,bp);
if(size < 60)
size = 60;
break;
case CL_SERIAL_LINE:
dump(iface,IF_TRACE_OUT,TYPE_IP,bp);
break;
case CL_AX25:
dump(iface,IF_TRACE_OUT,TYPE_AX25,bp);
break;
case CL_KISS:
dump(iface,IF_TRACE_OUT,TYPE_AX25,bp);
/* This *really* shouldn't be done here, but it was the
* easiest way. Put the type field for KISS TNC on front.
*/
if((bp1 = pushdown(bp,1)) == NULLBUF){
free_p(bp);
return -1;
}
bp = bp1;
bp->data[0] = KISS_DATA;
break;
}
if(bp->next != NULLBUF){
/* Copy to contiguous buffer, since driver can't handle mbufs */
bp1 = copy_p(bp,size);
free_p(bp);
bp = bp1;
if(bp == NULLBUF)
return -1;
} else
bp->cnt = size; /* Make sure packet size is big enough */
send_pkt(pp->intno,bp->data,bp->cnt);
free_p(bp);
return 0;
}
/* Packet driver receive routine. Called from an assembler hook that pushes
* the caller's registers on the stack so we can access and modify them.
* This is a rare example of call-by-location in C.
*/
void
pkint(dev,di,si,bp,dx,cx,bx,ax,ds,es)
unsigned short dev,di,si,bp,dx,cx,bx,ax,ds,es;
{
register struct pktdrvr *pp;
struct phdr *phdr;
if(dev >= Npk)
return; /* Unknown packet */
pp = &Pktdrvr[dev];
switch(ax){
case 0: /* Space allocate call */
if((pp->buffer = alloc_mbuf(cx+sizeof(struct phdr))) != NULLBUF){
es = FP_SEG(pp->buffer->data);
di = FP_OFF(pp->buffer->data+sizeof(struct phdr));
pp->buffer->cnt = cx + sizeof(struct phdr);
phdr = (struct phdr *)pp->buffer->data;
phdr->iface = pp->iface;
switch(pp->class){
case CL_ETHERNET:
phdr->type = TYPE_ETHER;
break;
case CL_SERIAL_LINE:
phdr->type = TYPE_IP;
break;
case CL_AX25:
phdr->type = TYPE_AX25;
break;
case CL_KISS:
phdr->type = TYPE_KISS;
break;
}
} else {
es = di = 0;
}
break;
case 1: /* Packet complete call */
enqueue(&Hopper,pp->buffer);
pp->buffer = NULLBUF;
break;
default:
break;
}
}
/* Shut down the packet interface */
static int
pk_stop(iface)
struct iface *iface;
{
struct pktdrvr *pp;
pp = &Pktdrvr[iface->dev];
/* Call driver's release_type() entry */
if(release_type(pp->intno,pp->handle1) == -1)
printf("%s: release_type error code %u\n",iface->name,Derr);
if(pp->class == CL_ETHERNET)
release_type(pp->intno,pp->handle2);
return 0;
}
/* Attach a packet driver to the system
* argv[0]: hardware type, must be "packet"
* argv[1]: software interrupt vector, e.g., x7e
* argv[2]: interface label, e.g., "trw0"
* argv[3]: maximum number of packets allowed on transmit queue, e.g., "5"
* argv[4]: maximum transmission unit, bytes, e.g., "1500"
*/
int
pk_attach(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register struct iface *if_pk;
int class;
unsigned int intno;
static char iptype[] = {IP_TYPE >> 8,IP_TYPE};
static char arptype[] = {ARP_TYPE >> 8,ARP_TYPE};
long drvvec;
char sig[8]; /* Copy of driver signature "PKT DRVR" */
register struct pktdrvr *pp;
if(Npk >= PK_MAX){
printf("Too many packet drivers\n");
return -1;
}
if(if_lookup(argv[2]) != NULLIF){
printf("Interface %s already exists\n",argv[2]);
return -1;
}
intno = htoi(argv[1]);
/* Verify that there's really a packet driver there, so we don't
* go off into the ozone (if there's any left)
*/
drvvec = (long)getvect(intno);
movblock(FP_OFF(drvvec)+3, FP_SEG(drvvec),
FP_OFF(sig),FP_SEG(sig),strlen(PKT_SIG));
if(strncmp(sig,PKT_SIG,strlen(PKT_SIG)) != 0){
printf("No packet driver loaded at int 0x%x\n",intno);
return -1;
}
if((if_pk = (struct iface *)calloc(1,sizeof(struct iface))) == NULLIF
||(if_pk->name = strdup(argv[2])) == NULLCHAR){
free((char *)if_pk);
printf("pk_attach: no memory!\n");
return -1;
}
pp = &Pktdrvr[Npk];
if_pk->mtu = atoi(argv[4]);
if_pk->dev = Npk++;
if_pk->raw = pk_raw;
if_pk->stop = pk_stop;
pp->intno = intno;
pp->iface = if_pk;
/* Find out by exhaustive search what class this driver is (ugh) */
for(class=0;class<9;class++){
pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
Pkvec[if_pk->dev]);
if(pp->handle1 != -1 || Derr == TYPE_INUSE)
break;
}
/* Now that we know, release it and do it all over again with the
* right type fields
*/
if(pp->handle1 != -1)
release_type(intno,pp->handle1);
switch(class){
case CL_ETHERNET:
pp->handle1 = access_type(intno,class,ANYTYPE,0,iptype,2,
Pkvec[if_pk->dev]);
pp->handle2 = access_type(intno,class,ANYTYPE,0,arptype,2,
Pkvec[if_pk->dev]);
if_pk->send = enet_send;
if_pk->output = enet_output;
/* Get hardware Ethernet address from driver */
if((if_pk->hwaddr = malloc(EADDR_LEN)) == NULLCHAR){
free(if_pk->name);
free((char *)if_pk);
printf("pk_attach: no memory!\n");
return -1;
}
get_address(intno,pp->handle1,if_pk->hwaddr,EADDR_LEN);
arp_init(ARP_ETHER,EADDR_LEN,IP_TYPE,ARP_TYPE,1,Ether_bdcst,pether,gether);
break;
#ifdef SLIP
case CL_SERIAL_LINE:
pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
Pkvec[if_pk->dev]);
if_pk->send = slip_send;
break;
#endif
#ifdef KISS
case CL_KISS: /* Note that the raw routine puts on the command */
pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
Pkvec[if_pk->dev]);
if_pk->send = ax_send;
if_pk->output = ax_output;
break;
#endif
#ifdef AX25
case CL_AX25:
pp->handle1 = access_type(intno,class,ANYTYPE,0,NULLCHAR,0,
Pkvec[if_pk->dev]);
if_pk->send = ax_send;
if_pk->output = ax_output;
break;
#endif
default:
printf("Packet driver has unsupported class %u\n",class);
free(if_pk->name);
free((char *)if_pk);
Npk--;
return -1;
}
pp->class = class;
if_pk->next = Ifaces;
Ifaces = if_pk;
return 0;
}
static int
access_type(intno,if_class,if_type,if_number,type,typelen,receiver)
int intno;
int if_class;
int if_type;
int if_number;
char *type;
unsigned typelen;
INTERRUPT (*receiver)();
{
union REGS regs;
struct SREGS sregs;
segread(&sregs);
regs.h.dl = if_number; /* Number */
sregs.ds = FP_SEG(type); /* Packet type template */
regs.x.si = FP_OFF(type);
regs.x.cx = typelen; /* Length of type */
sregs.es = FP_SEG(receiver); /* Address of receive handler */
regs.x.di = FP_OFF(receiver);
regs.x.bx = if_type; /* Type */
regs.h.ah = ACCESS_TYPE; /* Access_type() function */
regs.h.al = if_class; /* Class */
int86x(intno,®s,®s,&sregs);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
} else
return regs.x.ax;
}
static int
release_type(intno,handle)
int intno;
int handle;
{
union REGS regs;
regs.x.bx = handle;
regs.h.ah = RELEASE_TYPE;
int86(intno,®s,®s);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
} else
return 0;
}
static int
send_pkt(intno,buffer,length)
int intno;
char *buffer;
unsigned length;
{
union REGS regs;
struct SREGS sregs;
segread(&sregs);
sregs.ds = FP_SEG(buffer);
regs.x.si = FP_OFF(buffer);
regs.x.cx = length;
regs.h.ah = SEND_PKT;
int86x(intno,®s,®s,&sregs);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
} else
return 0;
}
#ifdef notdef
static int
driver_info(intno,handle,version,class,type,number,basic)
int intno;
int handle;
int *version,*class,*type,*number,*basic;
{
union REGS regs;
regs.x.bx = handle;
regs.h.ah = DRIVER_INFO;
regs.h.al = 0xff;
int86(intno,®s,®s);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
}
if(version != NULL)
*version = regs.x.bx;
if(class != NULL)
*class = regs.h.ch;
if(type != NULL)
*type = regs.x.dx;
if(number != NULL)
*number = regs.h.cl;
if(basic != NULL)
*basic = regs.h.al;
return 0;
}
#endif
static int
get_address(intno,handle,buf,len)
int intno;
int handle;
char *buf;
int len;
{
union REGS regs;
struct SREGS sregs;
segread(&sregs);
sregs.es = FP_SEG(buf);
regs.x.di = FP_OFF(buf);
regs.x.cx = len;
regs.x.bx = handle;
regs.h.ah = GET_ADDRESS;
int86x(intno,®s,®s,&sregs);
if(regs.x.cflag){
Derr = regs.h.dh;
return -1;
}
return 0;
}